using System.Collections;
using UnityEngine;
using UnityEditor;
using UnityEngine.UIElements;
using UnityEditor.UIElements;
using UnityEditor.Experimental.GraphView;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.ShaderGraph.Internal;
using System.IO;

public class GraphViewBase : GraphView
{
    public new class UxmlFactory : UxmlFactory<GraphViewBase, GraphView.UxmlTraits> { }
    private ContentZoomer mContentZoomer;
    private GraphViewData mData;

    private Label mFileNameLabel;
    private Button mSaveButton;
    private Button mReturnButton;
    private VisualElement mTopbar;

    private DropdownField mTitlePopup;

    private Stack<GraphNodeData> mSubViewStackData;

    private List<GraphNodeData> mCurrentNodes;

    public GraphViewBase()
    {
        var visualTree = Resources.Load<VisualTreeAsset>("UXML/GraphViewBase");
        visualTree.CloneTree(contentContainer);
        Insert(0, new GridBackground());

        this.AddManipulator(mContentZoomer = new ContentZoomer());
        this.AddManipulator(new ContentDragger());
        this.AddManipulator(new SelectionDragger());
        this.AddManipulator(new RectangleSelector());
        this.AddManipulator(new ClickSelector());

        mContentZoomer.maxScale = 20;
        mContentZoomer.minScale = 0.1f;

        mTopbar = this.Q("topbar");
        mFileNameLabel = this.Q<Label>("FileName");
        mSaveButton = this.Q<Button>("Save");
        mReturnButton = this.Q<Button>("ReturnButton");

        //mTitlePopup = this.Q<DropdownField>("TitlePopup");
        //mTitlePopup.choices = AssetDatabase.FindAssets("t: GraphViewData").Select(p =>
        // System.IO.Path.GetFileName(AssetDatabase.GUIDToAssetPath(p))).ToList();
        //if (mTitlePopup.choices.Count > 0)
        //{
        //    mTitlePopup.value = mTitlePopup.choices[0];
        //}

        mSaveButton.clicked += OnSaveClick;
        mReturnButton.clicked += OnReturnClick;

        mSubViewStackData = new Stack<GraphNodeData>();

        RegisterCallback<KeyDownEvent>(OnKeyDownEvent);
    }


    public void RefreshView(GraphViewData data)
    {
        mData = data;
        mSubViewStackData.Clear();
        RefreshView();
        if (mData)
        {
            UpdateViewTransform(mData.Position, mData.Scale);
        }
    }

    public void RefreshView()
    {
        //删除所有节点
        graphElements.ForEach(v => RemoveElement(v));

        if (mSubViewStackData.Count == 0)
        {
            if (mData == null) return;
            mCurrentNodes = mData.NodeDatas;
            mTopbar.visible = true;
            mReturnButton.visible = false;
            mFileNameLabel.text = mData == null ? "" : mData.name;
        }
        else
        {
            mTopbar.visible = false;
            mReturnButton.visible = true;
            mCurrentNodes = mSubViewStackData.Peek().Children;

            var CurrentName = mData == null ? "" : mData.name;
            foreach (var data in mSubViewStackData.ToList().Reverse<GraphNodeData>())
            {
                CurrentName += " > " + data.Title;
            }
            mFileNameLabel.text = CurrentName;
        }


        if (mCurrentNodes == null) return;

        for (int i = 0; i < mCurrentNodes.Count; i++)
        {
            CreateNode(mCurrentNodes[i]);
        }


        RefreshEdge();
    }

    private void RefreshEdge()
    {
        if (mData == null) return;

        var nodeDict = new Dictionary<int, GraphNode>();
        nodes.ForEach(element =>
        {
            var node = element as GraphNode;
            if (node != null)
            {
                var dataId = node.Data.GetInstanceID();
                nodeDict.Add(dataId, node);
            }
        });

        foreach (var nodeData in nodeDict.Values)
        {
            foreach (var child in nodeData.Data.Children)
            {
                nodeDict.TryGetValue(child.GetInstanceID(), out var childNode);
                if (childNode != null)
                {
                    var edge = nodeData.OutPort.ConnectTo(childNode.InPort);
                    AddElement(edge);
                }
            }
        }
    }

    protected virtual GraphNodeData CreateData()
    {
        return ScriptableObject.CreateInstance<GraphNodeData>();
    }

    private GraphNode CreateNode(GraphNodeData graphNodeData = null)
    {
        if (graphNodeData == null)
        {
            graphNodeData = CreateData();
        }
        var node = new GraphNode(graphNodeData);
        node.RegisterDoubleClickCallback((e) => { mSubViewStackData.Push((e.currentTarget as GraphNode).Data); RefreshView(); });
        AddElement(node);
        return node;
    }

    private void DeleteNode(GraphNode node)
    {
        RemoveElement(node);
    }

    public bool ElementContainsPoint(GraphElement element, Vector2 position)
    {
        return element.ContainsPoint(element.WorldToLocal(position));
    }
    public bool ElementContainsPoint<T>(List<T> elements, Vector2 position) where T : GraphElement
    {
        foreach (var element in elements)
        {
            if (element.ContainsPoint(element.WorldToLocal(position)))
            {
                return true;
            }
        }
        return false;
    }

    public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
    {
        if (mData == null) return;

        var selectionCount = selection.Count;

        var graphNodes = selection.Where(e => e is GraphNode).Select(e => e as GraphNode).ToList();
        var edges = selection.Where(e => e is Edge).Select(e => e as Edge).ToList();

        if (selectionCount > 0)
        {
            if (graphNodes.Count == selectionCount && ElementContainsPoint(graphNodes, evt.mousePosition))
            {
                OnBuildGraphNodeMenu(evt, graphNodes);
                return;
            }
            else if (edges.Count == selectionCount && ElementContainsPoint(edges, evt.mousePosition))
            {
                OnBuildEdgeMenu(evt, edges);
                return;
            }
        }

        OnBuildGraphViewMenu(evt);

    }

    protected virtual void OnBuildGraphNodeMenu(ContextualMenuPopulateEvent evt, List<GraphNode> graphNodes)
    {
        evt.menu.AppendAction("删除节点", (a) =>
        {
            graphNodes.ForEach(node => DeleteNode(node));
        });
        OnBuildGraphViewMenu(evt);
    }

    protected virtual void OnBuildEdgeMenu(ContextualMenuPopulateEvent evt, List<Edge> edges)
    {
        evt.menu.AppendAction("删除连线", (a) =>
        {
            edges.ForEach(edge => RemoveElement(edge));
        });
        OnBuildGraphViewMenu(evt);
    }

    protected virtual void OnBuildGraphViewMenu(ContextualMenuPopulateEvent evt)
    {
        evt.menu.AppendAction("创建节点", (a) =>
        {
            var node = CreateNode();
            var pos = node.WorldToLocal(a.eventInfo.mousePosition);
            node.style.left = pos.x;
            node.style.top = pos.y;
        });

        evt.menu.AppendAction("保存", (a) => OnSaveClick());
    }

    public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter)
    {
        return ports.ToList().Where(endPort =>
        {
            var connectable = endPort.direction != startPort.direction && endPort.node != startPort.node;
            return connectable;
        }).ToList();
    }

    public void RemoveNodeDataFromAsset(GraphNodeData graphNodeData)
    {
        foreach (var child in graphNodeData.Children)
        {
            RemoveNodeDataFromAsset(child);
        }
        AssetDatabase.RemoveObjectFromAsset(graphNodeData);
    }

    public void AddNodeDataToAsset(GraphViewData viewData, GraphNodeData graphNodeData)
    {
        foreach (var child in graphNodeData.Children)
        {
            AddNodeDataToAsset(viewData, child);
        }
        AssetDatabase.AddObjectToAsset(graphNodeData, viewData);
    }

    private void OnSaveClick()
    {
        if (mData == null) return;

        mCurrentNodes.ForEach(data => RemoveNodeDataFromAsset(data));
        mCurrentNodes.Clear();
        nodes.ForEach(element =>
        {
            var node = element as GraphNode;
            if (node != null)
            {
                node.Save();
                node.Data.hideFlags = HideFlags.HideInHierarchy;
                mCurrentNodes.Add(node.Data);
                AddNodeDataToAsset(mData, node.Data);
            }
        });

        mData.Position = viewTransform.position;
        mData.Scale = viewTransform.scale;

        EditorUtility.SetDirty(mData);
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();

    }

    public void OnReturnClick()
    {
        if (mSubViewStackData.Count > 0)
        {
            mSubViewStackData.Pop();
            RefreshView();
        }
    }

    public void OnKeyDownEvent(KeyDownEvent evt)
    {
        if (evt.keyCode == KeyCode.Backspace || evt.keyCode == KeyCode.Escape)
        {
            OnReturnClick();
        }
    }

}
